<div class="tmd-doc">
<p></p>
<h1 class="tmd-header-1">
The <code class="tmd-code-span">//go:build go1.mn</code> comment directives don't work with Go toolchain v1.22.x versions when no <code class="tmd-code-span">go.mod</code> files are involved
</h1>
<p></p>
<div class="tmd-usual">
Go 1.22 changed the semantics of <code class="tmd-code-span">for-range</code> and tranditional <code class="tmd-code-span">for;;</code> loops. Since the semantic changes alter the behavior of existing code written according to the previous semantics, they break backward compatibility.
</div>
<p></p>
<div class="tmd-usual">
While <code class="tmd-code-span">for-range</code> loops are almost unaffected, traditional <code class="tmd-code-span">for;;</code> loops <a href="https://go101.org/blog/2024-03-01-for-loop-semantic-changes-in-go-1.22.html">exhibit unexpected behaviors due to the breakage</a>.
</div>
<p></p>
<p></p>
<div class="tmd-usual">
To keep using the old semantics prior to Go 1.22 in Go 1.22+ age, we must specify a Go version for each Go source file. One way to achieve this is adding a <code class="tmd-code-span">//go:build go1.21</code> comment directive at the beginning of the Go source file containing the old code.
</div>
<p></p>
<div class="tmd-usual">
While officially documented, due to <a href="https://github.com/golang/go/issues/66092">a known bug</a>, this way is currently non-functional with Go toolchain 1.22.x versions.
</div>
<p></p>
<p></p>
<div class="tmd-usual">
Here, I simply describe this bug: for a Go source file which Go version is not specified in a <code class="tmd-code-span">go.mod</code> file, the <code class="tmd-code-span">//go:build go1.mn</code> comment directive in it fails to specify the Go verison for it.
</div>
<p></p>
<div class="tmd-usual">
Here is an example:
</div>
<p></p>
<pre class="tmd-code">
<code class="language-Go">//go:build go1.21
package main

import "fmt"

func filter(n int) bool {
	return n&amp;0xF == 0
}

// Search values and return them without perversing order.
func search(start, end int) (r []int) {
	var count = 0
	for i, index := start, 0; i &lt;= end; i++ {
		if filter(i) {
			count++
			defer func(value int) {
				r[index] = value
				index++
			}(i)
		}
	}

	r = make([]int, count)
	return
}

func main() {
    fmt.Println(search(10, 36))
}
</code></pre>
<p></p>
<div class="tmd-usual">
When run the Go file as a script with the <code class="tmd-code-span">go run</code> command (without a <code class="tmd-code-span">go.mod</code> file involved), the example program prints <code class="tmd-code-span">[16 0]</code> with Go toolchain 1.22.x versions, due to Go 1.22+ semantics are used, which is wrongly. It should prints <code class="tmd-code-span">[32 16]</code>, as with older (1.21-) and newer (1.23+) toolchain versions. <sup><a id="fn:gotv:ref-1" href="#fn:gotv">[1]</a></sup>
</div>
<p></p>
<pre class="tmd-code">
$ gotv 1.21 run a.go
[Run]: $HOME/.cache/gotv/tag_go1.21.13/bin/go run a.go
[32 16]
$ gotv 1.22 run a.go
[Run]: $HOME/.cache/gotv/tag_go1.22.12/bin/go run a.go
[16 0]
$ gotv 1.23 run a.go
[Run]: $HOME/.cache/gotv/tag_go1.23.9/bin/go run a.go
[32 16]
</pre>
<p></p>
<div class="tmd-usual">
The Go core team deliberately <a href="https://github.com/golang/go/issues/66092#issuecomment-2192570381">refused to fix the bug for 1.22.x versions</a>. So you should be aware of the fact that the bug will be always in 1.22.x versions when you are using them to develop Go projects.
</div>
<p></p>
<p></p>
<hr  class="tmd-seperator"/>
<p></p>

<ol class="tmd-list tmd-footnotes" id="fn:">
<li id="fn:gotv" class="tmd-list-item tmd-footnote-item">
<div id="gotv" class="tmd-usual">
GoTV (<a href="https://go101.org/apps-and-libs/gotv.html">https://go101.org/apps-and-libs/gotv.html</a>) is a tool used to install and use coexisting installations of Go toolchain verisons harmoniously.
</div>
<a href="#fn:gotv:ref-1">↩︎</a></li>
</ol>
</div>
